package com.tcoding.client.controller.sidemenu;

import com.jfoenix.assets.JFoenixResources;
import com.jfoenix.controls.*;
import com.jfoenix.svg.SVGGlyph;
import com.sun.javafx.scene.control.skin.LabeledText;
import com.tcoding.client.AppStart;
import com.tcoding.client.bean.MenuVoCell;
import com.tcoding.client.controller.contextmenu.GlobalMenu;
import com.tcoding.client.controller.feature.FeatureResourceConsumer;
import com.tcoding.client.event.CustomEventListener;
import com.tcoding.client.event.CustomEventManager;
import com.tcoding.client.event.GlobalContextMenuActionEvent;
import com.tcoding.client.store.ApplicationStore;
import com.tcoding.client.utils.SvgGraphicUtil;
import com.tcoding.core.vo.MenuVO;
import io.datafx.controller.ViewController;
import io.datafx.controller.flow.Flow;
import io.datafx.controller.flow.FlowException;
import io.datafx.controller.flow.FlowHandler;
import io.datafx.controller.flow.container.AnimatedFlowContainer;
import io.datafx.controller.flow.container.ContainerAnimations;
import io.datafx.controller.flow.context.FXMLViewFlowContext;
import io.datafx.controller.flow.context.ViewFlowContext;
import javafx.beans.property.ListProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.event.EventTarget;
import javafx.fxml.FXML;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.Tab;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.text.TextAlignment;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javafx.util.Duration;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.controlsfx.glyphfont.Glyph;
import org.kordamp.ikonli.javafx.FontIcon;

import javax.annotation.PostConstruct;
import javax.inject.Inject;
import java.lang.reflect.InvocationTargetException;
import java.util.*;

@Slf4j
@ViewController(value = "/fxml/SideMenu.fxml", title = "Material Design Example")
public class SideMenuController {

    @FXMLViewFlowContext
    private ViewFlowContext context;
    @FXML
    private JFXListView<Object> customerSideList;
    @Inject
    private FeatureResourceConsumer featureResourceConsumer;

    private JFXTabPane mainTabPane;

    private ObservableValue<Boolean> menuExpand;


    /**
     * init fxml when loaded.
     */
    @PostConstruct
    public void init() {
        Objects.requireNonNull(context, "context");
        JFXTabPane tabPane = (JFXTabPane) context.getRegisteredObject("ContentPane");
        context.register("mainLeftMenu",customerSideList);
        this.mainTabPane = tabPane;
        //清空
        tabPane.getTabs().clear();
        customerSideList.getItems().clear();
        initMenu();
        registListener();
        customerSideList.propagateMouseEventsToParent();
        ObservableList<Object> items = customerSideList.getItems();
//        Iterator<Object> iterator = items.stream().iterator();
//        customerSideList.getSelectionModel().selectedItemProperty().addListener((o, oldVal, newVal) -> new Thread(() -> {
//            Platform.runLater(() -> {
//                if (newVal != null) {
//                    try {
//                        if (newVal instanceof Label) {
//                            Label menuVO = (Label) newVal;
//                            addTab(menuVO.getText(), null, MenuConstant.globalLinkMap.get(menuVO.getId()), menuVO.getUserData(), tabPane);
//                        }
//                    } catch (ClassNotFoundException e) {
//                        e.printStackTrace();
//                    }
//                }
//            });
//        }).start());

//        while (iterator.hasNext()) {
//            Object next1 = iterator.next();
//            if (next1 instanceof Label) {
//                System.out.println("adsdad...." + ((Label) next1).getText());
//            } else {
//                JFXListView<Label> next = (JFXListView<Label>) next1;
//                next.getSelectionModel().selectedItemProperty().addListener((o, oldVal, newVal) -> new Thread(() -> {
//                    Platform.runLater(() -> {
//                        if (newVal != null) {
//                            try {
//                                addTab(newVal.getText(), null, MenuConstant.globalLinkMap.get(newVal.getId()), newVal.getUserData(), tabPane);
//                            } catch (ClassNotFoundException e) {
//                                e.printStackTrace();
//                            }
//                        }
//                    });
//                }).start());
//            }
//
//
//        }
        ///设置首页
        String dashboardText = StringUtils.equals(Locale.getDefault().getLanguage(), "zh") ? "首页" : "home";
        try {
            addTab(dashboardText, null,"com.tcoding.client.controller.uicomponents.HomeController", "home", tabPane);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        tabPane.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {

            if (newValue != null) {
                String text = newValue.getText();
                int j = 0;
                for (Object jfxListView : items) {
                    if (jfxListView instanceof Label) {
                        if(StringUtils.equals(text,((Label) jfxListView).getText())){
                            customerSideList.getSelectionModel().select(jfxListView);
                            break;
                        }
                        continue;
                    }
                    JFXListView<Label> jfxListView2 = (JFXListView<Label>) jfxListView;
                    ObservableList<Label> listViewItems = jfxListView2.getItems();
                    for (int i = 0; i < listViewItems.size(); i++) {
                        Label label = listViewItems.get(i);
                        if (label.getText().equals(text)) {
                            jfxListView2.getSelectionModel().select(i);
//                        customerSideList.getSelectionModel().select(j);
                            break;
                        }
                    }
                    j++;
                }
            }

        });
    }

    private void initMenu() {
        MenuConstant.TABS_MAP.clear();
        MenuConstant.GLOBAL_LINK_MAP.clear();
        ListProperty<MenuVoCell> listProperty = ApplicationStore.getMenuVoCells();
        listProperty.sort(Comparator.comparing(o -> o.getMenuVO().getOrderNum()));
        for (MenuVoCell menuVoCell : listProperty) {
            String menuText = StringUtils.equals(Locale.getDefault().getLanguage(), "zh") ? menuVoCell.getMenuVO().getTitle() : menuVoCell.getMenuVO().getCode();

            if (menuVoCell.getChildrenMenus().isEmpty()) {
                FontIcon fontIcon = new FontIcon(StringUtils.isBlank(menuVoCell.getMenuVO().getIcon()) ? "fas-smile" : menuVoCell.getMenuVO().getIcon());
                fontIcon.setIconSize(12);
                Label nodeLabel = new Label(menuText, fontIcon);
                nodeLabel.setId(menuVoCell.getMenuVO().getCode());
                nodeLabel.setUserData(menuVoCell.getMenuVO());
                nodeLabel.getStyleClass().add("first-label");
                MenuConstant.GLOBAL_LINK_MAP.put(menuVoCell.getMenuVO().getCode(), menuVoCell.getMenuVO().getHref());
                customerSideList.getItems().add(nodeLabel);
                customerSideList.setOnMouseClicked(e->{
                    EventTarget target = e.getTarget();
                    Label clickedTarget=null;
                    if(target instanceof  Label){
                        clickedTarget = (Label)target;
                    }else if (target instanceof ListCell) {
                        ListCell<Label> target1 = (ListCell) target;
                        clickedTarget = (Label)target1.getGraphic();
                    }else if( target instanceof LabeledText){
                        clickedTarget = (Label)((LabeledText) target).getParent();
                    }

                    if(clickedTarget == null){
                        return;
                    }
                    MenuVO menuVO = (MenuVO)clickedTarget.getUserData();
                    try {
                        addTab(menuVO.getTitle(), null, MenuConstant.GLOBAL_LINK_MAP.get(menuVO.getCode()), menuVO, mainTabPane);
                    } catch (ClassNotFoundException ex) {
                        ex.printStackTrace();
                    }
                });

            } else {
                JFXListView<Label> listView = new JFXListView<>();
                listView.getStyleClass().add("sublist");
                Label label = null;
                try {
                    FontIcon fontIcon = new FontIcon(StringUtils.isBlank(menuVoCell.getMenuVO().getIcon()) ? "fas-smile" : menuVoCell.getMenuVO().getIcon());
                    fontIcon.setIconSize(12);
                    label = new Label(menuText, fontIcon);
                    label.getStyleClass().add("sub-label");
                    label.setUserData(menuVoCell);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                Objects.requireNonNull(label).setTextAlignment(TextAlignment.LEFT);
                listView.setGroupnode(label);
                ObservableList<MenuVO> childrenMenus = menuVoCell.getChildrenMenus();
                childrenMenus.sort(Comparator.comparing(MenuVO::getOrderNum));
                for (MenuVO menuVO : childrenMenus) {
                    String childMenuText = StringUtils.equals(Locale.getDefault().getLanguage(), "zh") ? menuVO.getTitle() : menuVO.getCode();
                    Label nodeLabel = new Label(childMenuText);
                    nodeLabel.setId(menuVO.getCode());
                    nodeLabel.setUserData(menuVO);
                    MenuConstant.GLOBAL_LINK_MAP.put(menuVO.getCode(), menuVO.getHref());
                    listView.getItems().add(nodeLabel);
                }


                listView.setOnMouseClicked(e->{
                    EventTarget target = e.getTarget();
                    Label clickedTarget=null;
                    if(target instanceof  Label){
                        clickedTarget = (Label)target;
                    }else if (target instanceof ListCell) {
                        ListCell<Label> target1 = (ListCell) target;
                        clickedTarget = (Label)target1.getGraphic();
                    }else if( target instanceof LabeledText){
                        clickedTarget = (Label)((LabeledText) target).getParent();
                    }

                    if(clickedTarget == null){
                        return;
                    }
                    MenuVO menuVO = (MenuVO)clickedTarget.getUserData();
                    try {
                        addTab(menuVO.getTitle(), null, MenuConstant.GLOBAL_LINK_MAP.get(menuVO.getCode()), menuVO, mainTabPane);
                    } catch (ClassNotFoundException ex) {
                        ex.printStackTrace();
                    }
                });

                customerSideList.getItems().add(listView);
            }
        }
    }

    /**
     * @Description:添加tab页
     * @param: [flow]
     * @return: void
     * @auther: liwen
     * @date: 2020/6/28 9:57 上午
     */
    public static <T> void addTab(String title, Node icon, String uri, Object userData, JFXTabPane tabPane) throws ClassNotFoundException {
        ApplicationStore.showProgress();
        if(StringUtils.startsWithAny(uri,"http","https")){
            openInBrowser(uri,title,userData,tabPane);
            return;
        }

        Flow flow = new Flow(Class.forName(uri));
        FlowHandler flowHandler = flow.createHandler();
        if (userData instanceof String) {
            openInTab(title, icon, flow, userData, tabPane, flowHandler);
        } else {
            MenuVO menuVO = (MenuVO) userData;
            if (StringUtils.equals(menuVO.getOpenType(), "1")) {
                openInNewWindow(flowHandler,title,icon,userData);
            } else {
                openInTab(title, icon, flow, userData, tabPane, flowHandler);
            }
        }
    }

    public static void openInBrowser(String uri,String title,Object userData,JFXTabPane tabPane){
        String tabId = "";
        if(userData instanceof String){
            tabId = userData.toString();
        }else {
            MenuVO menuVO = (MenuVO) userData;
            tabId = menuVO.getCode();
        }

        Tab tab = MenuConstant.TABS_MAP.get(title);
        if (tab == null) {
            tab = new Tab(title);
            tab.setId(tabId);
            tab.setUserData(userData);
            WebView webView = new WebView();
            final WebEngine webEngine = webView.getEngine();
            webEngine.load(uri);

            VBox content = new VBox();
            StackPane node = new StackPane();

            HBox searchBox = new HBox();
            searchBox.setSpacing(5.0);

            //导航前进后退
            JFXButton left = new JFXButton();
            left.setDisable(true);
            left.setButtonType(JFXButton.ButtonType.RAISED);
            left.setStyle("-fx-text-fill:WHITE;-fx-background-color:#5264AE;-fx-font-size:14px;");
            SVGGlyph leftIcon = SvgGraphicUtil.buildSvgGraphic("angle-left", 14,Color.WHITE);
            left.setGraphic(leftIcon);

            JFXButton refresh = new JFXButton();
            refresh.setButtonType(JFXButton.ButtonType.RAISED);
            refresh.setStyle("-fx-text-fill:WHITE;-fx-background-color:#5264AE;-fx-font-size:14px;");
            SVGGlyph refreshIcon = SvgGraphicUtil.buildSvgGraphic("refresh", 14,Color.WHITE);
            refresh.setGraphic(refreshIcon);

            JFXButton right = new JFXButton();
            right.setDisable(true);
            right.setStyle("-fx-text-fill:WHITE;-fx-background-color:#5264AE;-fx-font-size:14px;");
            right.setButtonType(JFXButton.ButtonType.RAISED);
            SVGGlyph rightIcon = SvgGraphicUtil.buildSvgGraphic("angle-right", 14,Color.WHITE);
            right.setGraphic(rightIcon);
            TextField locationField = new TextField();
            locationField.textProperty().bind(webEngine.locationProperty());
            locationField.getStyleClass().add("cf-text-field");
            JFXButton button = new JFXButton("搜索");
            button.setStyle("-fx-text-fill:WHITE;-fx-background-color:#5264AE;-fx-font-size:14px;");
            SVGGlyph searchIcon = SvgGraphicUtil.buildSvgGraphic("search", 14,Color.WHITE);
            button.setButtonType(JFXButton.ButtonType.RAISED);
            button.setGraphic(searchIcon);
            webEngine.getHistory().currentIndexProperty().addListener((ob,o,n)->{
                System.out.println("当前索引："+n.intValue());
                if(n.intValue()>0){
                    left.setDisable(false);
                }else {
                    left.setDisable(true);
                }
                if( webEngine.getHistory().getEntries().size()>(n.intValue()+1)){
                    right.setDisable(false);
                }else {
                    right.setDisable(true);
                }
            });
            left.setOnAction((e)-> webEngine.getHistory().go(-1));
            refresh.setOnAction((e)->webEngine.reload());
            right.setOnAction((e)-> webEngine.getHistory().go(1));
            button.setOnAction((e)-> webEngine.load(locationField.getText()));
            searchBox.setPadding(new Insets(2, 5, 2, 5));
            searchBox.setAlignment(Pos.CENTER_LEFT);
            searchBox.getChildren().addAll(left,refresh,right,locationField,button);
            HBox.setHgrow(locationField, Priority.ALWAYS);

            node.getChildren().add(webView);
            node.getStyleClass().addAll("tab-content");
            node.setPadding(new Insets(0, 0, 0, 0));
            content.getChildren().addAll(searchBox,node);
            VBox.setVgrow(node,Priority.ALWAYS);

            tab.textProperty().bind(webEngine.titleProperty());
            tab.setContent(content);
            tabPane.getTabs().add(tab);
            MenuConstant.TABS_MAP.put(title, tab);
            tab.setOnClosed(event -> {
                MenuConstant.TABS_MAP.remove(title);
            });
            tab.setContextMenu(GlobalMenu.getInstance(tab.getUserData()));
        }

        if (StringUtils.equals(title, "home") || StringUtils.equals(title, "首页")) {
            tab.setClosable(false);
        }
        tabPane.getSelectionModel().select(tab);

        ApplicationStore.hideProgress();
    }

    public void openBrowserInNewWindow(String uri,String title){
        WebView webView = new WebView();
        final WebEngine webEngine = webView.getEngine();
        webEngine.load(uri);
        Scene scene = new Scene(webView);
        Stage newStage = new Stage();
        newStage.setWidth(800);
        newStage.setHeight(600);
        newStage.setTitle(title);
        newStage.setScene(scene);
        newStage.show();
        ApplicationStore.hideProgress();
    }

    public static void openInNewWindow(FlowHandler flowHandler,String title, Node icon,Object userData) {
        StackPane node = null;
        try {
            node = flowHandler.start(new AnimatedFlowContainer(Duration.millis(320), ContainerAnimations.SWIPE_LEFT));
            node.setPadding(new Insets(10));
            Scene scene = new Scene(node);
            final ObservableList<String> stylesheets = scene.getStylesheets();
            stylesheets.addAll(JFoenixResources.load("css/jfoenix-fonts.css").toExternalForm(),
                    JFoenixResources.load("css/jfoenix-design.css").toExternalForm(),
                    AppStart.class.getResource("/css/chenfei/color.css").toExternalForm(),
                    AppStart.class.getResource("/css/chenfei/core.css").toExternalForm(),
                    AppStart.class.getResource("/css/theme/jfoenix-main-dark.css").toExternalForm()
            );
            Stage newStage = new Stage();
            newStage.setWidth(800);
            newStage.setHeight(600);
            newStage.setTitle(title);
            newStage.setScene(scene);
            newStage.show();
            newStage.setOnCloseRequest(action -> {
                // TODO: 2022/9/6

            });
        } catch (FlowException e) {
            e.printStackTrace();
        }
        ApplicationStore.hideProgress();
    }

    private static void openInTab(String title, Node icon, Flow flow, Object userData, JFXTabPane tabPane, FlowHandler flowHandler) {

        String tabId = "";
        if(userData instanceof String){
            tabId = userData.toString();
        }else {
            MenuVO menuVO = (MenuVO) userData;
            tabId = menuVO.getCode();
        }

        Tab tab = MenuConstant.TABS_MAP.get(title);
        if (tab == null) {
            tab = new Tab(title);
            tab.setId(tabId);
            tab.setGraphic(icon);
            tab.setUserData(userData);
            try {
                StackPane node = flowHandler.start(new AnimatedFlowContainer(Duration.millis(320), ContainerAnimations.FADE));
                node.getStyleClass().addAll("tab-content");
                node.setPadding(new Insets(10, 10, 15, 10));
                tab.setContent(node);

            } catch (FlowException e) {
                e.printStackTrace();
            }
            tabPane.getTabs().add(tab);
            MenuConstant.TABS_MAP.put(title, tab);
            tab.setOnClosed(event -> {
                MenuConstant.TABS_MAP.remove(title);
                try {
                    flowHandler.getCurrentViewContext().destroy();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            });

            tab.setContextMenu(GlobalMenu.getInstance(tab.getUserData()));

        }

        if (StringUtils.equals(title, "home") || StringUtils.equals(title, "首页")) {
            tab.setClosable(false);
        }
        tabPane.getSelectionModel().select(tab);
        ApplicationStore.hideProgress();
    }

    private void registListener(){
        CustomEventManager.addListener(new CustomEventListener<GlobalContextMenuActionEvent>() {

            /**
             * 处理器
             *
             * @param globalContextMenuActionEvent
             */
            @Override
            public void handler(GlobalContextMenuActionEvent globalContextMenuActionEvent) throws ClassNotFoundException {
                Object value = null;
                switch (globalContextMenuActionEvent.getAction()){

                    case OPEN:
                        value = globalContextMenuActionEvent.getValue();
                        if(!(value instanceof MenuVO)){
                            return;
                        }
                        MenuVO menuVO = (MenuVO) value;
                        String s = MenuConstant.GLOBAL_LINK_MAP.get(menuVO.getCode());
                        if(StringUtils.startsWithAny(s,"http","https")){
                            mainTabPane.getTabs().removeIf(tab -> StringUtils.equals(tab.getId(), menuVO.getCode()));
                            MenuConstant.TABS_MAP.remove(menuVO.getTitle());
                            openBrowserInNewWindow(s, menuVO.getTitle());
                            return;
                        }
                        Flow flow = new Flow(Class.forName(s));
                        FlowHandler flowHandler = flow.createHandler();
                        mainTabPane.getTabs().removeIf(tab -> StringUtils.equals(tab.getId(), menuVO.getCode()));
                        MenuConstant.TABS_MAP.remove(menuVO.getTitle());
                        openInNewWindow(flowHandler, menuVO.getTitle(), null,menuVO);
                        break;
                    case CLOSE_ALL:
                        Iterator<Map.Entry<String, Tab>> iterator = MenuConstant.TABS_MAP.entrySet().iterator();
                        while (iterator.hasNext()){
                            Map.Entry<String, Tab> next = iterator.next();
                            if(StringUtils.equalsAny(next.getKey(),"首页","home")){
                                continue;
                            }
                            iterator.remove();
                        }
                        mainTabPane.getTabs().removeIf(tab -> !StringUtils.equalsAny(tab.getId(),"首页","home"));
                        break;
                    case CLOSE_CURRENT:
                        value = globalContextMenuActionEvent.getValue();
                        if(!(value instanceof MenuVO)){
                            return;
                        }
                        MenuVO currentMenu = (MenuVO) value;
                        mainTabPane.getTabs().removeIf(tab -> StringUtils.equals(tab.getId(), currentMenu.getCode()));
                        MenuConstant.TABS_MAP.remove(currentMenu.getTitle());
                        break;
                    case CLOSE_RIGHT:
                        String currentTile = "";
                        Iterator<Map.Entry<String, Tab>> iterator1 = MenuConstant.TABS_MAP.entrySet().iterator();
                        value = globalContextMenuActionEvent.getValue();
                        if(!(value instanceof MenuVO)){
                            Object[] objects = MenuConstant.TABS_MAP.entrySet().toArray();
                            currentTile = ((Map.Entry) objects[0]).getKey().toString();
                        }else {
                            MenuVO currentMenu2 = (MenuVO) value;
                            currentTile = currentMenu2.getTitle();
                        }
                        int index=1,fromIndex = 1;
                        while (iterator1.hasNext()){
                            if(StringUtils.equals(iterator1.next().getKey(),currentTile)){
                                fromIndex = index;
                            }else {
                                index++;
                            }
                            if(index>fromIndex){
                                iterator1.remove();
                            }
                        }
                        mainTabPane.getTabs().remove(fromIndex,mainTabPane.getTabs().size());
                        break;
                    default:
                }

            }
        });
    }
}
